package org.oimwrapper.connectors.common;

import Thor.API.*;
import Thor.API.Operations.*;
import com.thortech.xl.dataobj.*;
import java.util.*;

import org.oimwrapper.connectors.*;

/**
 * Scans for recon events with an event received status and attempts to re-process them.<p>
 *
 * This task expects the following parameters, in addition to the standard
 * parameters in the {@link OIMTaskBase} class.
 * <ul>
 * <li><code>ResourceName</code> The name of the resource object to search for events from.</li>
 * <li><code>EventStatus</code> The status of the events to search for.  This defaults to 'event received'.</li>
 * <li><code>StartDate</code> The start date to begin looking for recon events on, in yyyy-MM-dd format.  This
 *                            defaults to the beginning of time.</li>
 * <li><code>Threads</code> The number of concurrent threads to run to submit events to OIM.  By default, ten
 *                          submitting threads are run.</li>
 * </ul>
 */
public class OIMResubmitReconEvents extends OIMTaskBase {

	/**
	 * True if a stop has been requested for this task.
	 */
	private boolean stop;
	
	/**
	 * The recon operations instance used by this task.
	 */
	private tcReconciliationOperationsIntf reconOp;
    
	/**
	 * Default constructor.
	 */
	public OIMResubmitReconEvents() {
		super("OIMWRAPPER.TASK");
		stop = false;
	}

	/**
	 * This method is called by the scheduler to execute the task instance.
	 */
	public final void execute() {
		logger.debug("Entering resubmitReconEvents.execute()");
		try {
			checkOimVersion("9.1");
			reconOp = (tcReconciliationOperationsIntf) getUtility(tcReconciliationOperationsIntf.class);
			Map searchFor = new HashMap();
			long objectKey = getResourceObject(getDefaultAttribute("ResourceName", ""));
			if (objectKey != 0L) {
				searchFor.put("Objects.Key", Long.toString(objectKey));
			}
			searchFor.put("Reconciliation Manager.Status", getDefaultAttribute("EventStatus", tcRCE.STATUS_INITIAL));
			String startDate = getDefaultAttribute("StartDate", formatDate((new java.util.Date(0)).getTime(), "yyyy-MM-dd"));
			String endDate = formatDate((new java.util.Date()).getTime(), "yyyy-MM-dd");
			tcResultSet results = reconOp.findReconciliationEvent(searchFor, startDate, endDate);
			int maxWorkers = Integer.parseInt(getDefaultAttribute("Threads", "10"));
			for (int i = 0; !stop && i < results.getRowCount(); i++) {
				results.goToRow(i);
				logger.debug("Processing event " + Integer.toString(i + 1) + " of " + Integer.toString(results.getRowCount()));
				long eventKey = results.getLongValue("Reconciliation Manager.Key");
				startThread(maxWorkers, new worker(this, eventKey));
			}
			waitForAllThreads();
		} catch (Exception e) {
			OIMExceptionHandler.handleException(logger, e, getClass());
		}
		logger.debug("Exiting resubmitReconEvents.execute()");
	}

	/**
	 * This method is called by the scheduler to stop a running task instance.
	 * 
	 * @return <code>true</code>
	 */
	public final boolean stop() {
		logger.debug("Entering resubmitReconEvents.stop()");
		logger.warn(" ---- Stopping current task ---- ");
		stop = true;
		logger.debug("Exiting resubmitReconEvents.stop()");
		return stop;
	}
	
	/**
	 * Processes a single recon event.
	 * 
	 * @param EventKey The event key of the event to process.
	 */
	private void processSingleEvent(long EventKey) {
		try {
			reconOp.processReconciliationEvent(EventKey);
		} catch (Exception e) {
			OIMExceptionHandler.handleException(logger, e, getClass());
		}
	}
	
	/**
	 * Worker Thread.
	 */
	private class worker extends OIMTaskThreadBase {
		
		/**
		 * The invoking task.
		 */
		private OIMResubmitReconEvents task;
		
		/**
		 * The record to process.
		 */
		private long eventKey;
		
		/**
		 * Default Constructor.
		 * 
		 * @param Task The invoking task.
		 * @param EventKey The event key of the recon event to process.
		 */
		private worker(OIMResubmitReconEvents Task, long EventKey) {
			super(Task);
			task = Task;
			eventKey = EventKey;
		}
		
		/**
		 * Processes and submits a single recon event.
		 */
		public void runOimThread() {
			task.processSingleEvent(eventKey);
		}
	}
}